package com.atguigu.gmall.activity.service.impl;

import com.atguigu.gmall.activity.mapper.ActivityInfoMapper;
import com.atguigu.gmall.activity.mapper.ActivityRuleMapper;
import com.atguigu.gmall.activity.mapper.ActivitySkuMapper;
import com.atguigu.gmall.activity.mapper.CouponInfoMapper;
import com.atguigu.gmall.activity.service.ActivityInfoService;
import com.atguigu.gmall.model.activity.*;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.cart.CartInfoVo;
import com.atguigu.gmall.model.enums.ActivityType;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author atguigu-mqx
 */
//  实现类中可能会用到单表的CURD 方法！
@Service
public class ActivityInfoServiceImpl extends ServiceImpl<ActivityInfoMapper, ActivityInfo> implements ActivityInfoService {

    @Autowired
    private ActivityInfoMapper activityInfoMapper;

    @Autowired
    private ActivityRuleMapper activityRuleMapper;

    @Autowired
    private ActivitySkuMapper activitySkuMapper;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private CouponInfoMapper couponInfoMapper;


    @Override
    public IPage<ActivityInfo> getPage(Page<ActivityInfo> pageParam) {
        //  定义一个查询条件的排序功能：
        QueryWrapper<ActivityInfo> activityInfoQueryWrapper = new QueryWrapper<>();
        activityInfoQueryWrapper.orderByDesc("id");
        //  细节处理： activityTypeString
        Page<ActivityInfo> activityInfoPage = activityInfoMapper.selectPage(pageParam, activityInfoQueryWrapper);
        //  赋值类型名称
        activityInfoPage.getRecords().stream().forEach(item->{
            item.setActivityTypeString(ActivityType.getNameByType(item.getActivityType()));
        });
        //  返回数据：
        return activityInfoPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 如果有异常记得回滚数据！
    public void saveActivityRule(ActivityRuleVo activityRuleVo) {

        //  次方法除了保存之外，还可能有一些修改的内容！
        //  先删除对应的数据，然后新增！
        activityRuleMapper.delete(new QueryWrapper<ActivityRule>().eq("activity_id",activityRuleVo.getActivityId()));

        activitySkuMapper.delete(new QueryWrapper<ActivitySku>().eq("activity_id",activityRuleVo.getActivityId()));

        //  活动的优惠券进行绑定！ 重点：coupon_info 表中 如果 activity_id 有数据的话，就说明当前优惠券与活动有绑定关系！
        //  在绑定之前先将 coupon_info.activity_id=0 ;  0 或者 null 说明这个优惠券都与活动没有关系！
        CouponInfo couponInfo = new CouponInfo();
        couponInfo.setActivityId(0L);
        //  在做保存的时候：activityRuleVo.getActivityId() 一定是有数据的！
        couponInfoMapper.update(couponInfo,new QueryWrapper<CouponInfo>().eq("activity_id",activityRuleVo.getActivityId()));


        //  保存数据即可！
        //  保存活动规则，保存参与活动的商品！优惠券列表暂时先不做处理！{等优惠券讲完才能做}

        //  获取到活动规则数据
        List<ActivityRule> activityRuleList = activityRuleVo.getActivityRuleList();

        //  获取到参与活动的商品集合数据
        List<ActivitySku> activitySkuList = activityRuleVo.getActivitySkuList();

        //  新增数据
        if (!CollectionUtils.isEmpty(activityRuleList)){
            //  循环遍历插入数据
            for (ActivityRule activityRule : activityRuleList) {
                //  页面传递的时候，需要将活动Id 赋值 activityRuleVo.activityId
                activityRule.setActivityId(activityRuleVo.getActivityId());
                activityRuleMapper.insert(activityRule);
            }
        }

        if (!CollectionUtils.isEmpty(activitySkuList)){
            //  循环遍历插入数据
            for (ActivitySku activitySku : activitySkuList) {
                //  页面传递的时候，需要将活动Id 赋值 activityRuleVo.activityId
                activitySku.setActivityId(activityRuleVo.getActivityId());
                activitySkuMapper.insert(activitySku);
            }
        }
        //  设置绑定关系
        List<Long> couponIdList = activityRuleVo.getCouponIdList();
        //  判断
        if (!CollectionUtils.isEmpty(couponIdList)){
            //  循环遍历
            for (Long couponId : couponIdList) {
                CouponInfo couponInfoUpd = new CouponInfo();
                couponInfoUpd.setId(couponId);
                couponInfoUpd.setActivityId(activityRuleVo.getActivityId());
                couponInfoMapper.updateById(couponInfoUpd);
            }
        }

    }

    @Override
    public List<SkuInfo> findSkuInfoByKeyword(String keyword) {
        /*
        1.	获取到所有的skuInfo 列表 根据用户输入的keyword ！
        2.	将skuInfo列表 中 skuId 组成一个新的集合！
        3.	查询出skuId 这个集合列表中有哪些商品参与了活动的！
        4.	只需要去重
         */
        //  根据到根据关键字查询到的所有集合数据列表
        List<SkuInfo> skuInfoList = productFeignClient.findSkuInfoByKeyword(keyword);
        //  根据skuInfoList 转换成 以skuId 为基准的集合
        List<Long> skuIdList = skuInfoList.stream().map(SkuInfo::getId).collect(Collectors.toList());

        //  查询出skuId 这个集合列表中有哪些商品参与了活动的！
        //  existSkuIdList 表示获取到当前活动列表的skuId 集合
        List<Long> existSkuIdList =  activityInfoMapper.selectExistSkuIdList(skuIdList);

        //  准备去重复
        //  获取到已经参加活动的商品列表
        List<SkuInfo> skuInfos = existSkuIdList.stream().map(skuid -> productFeignClient.getSkuInfo(skuid)).collect(Collectors.toList());
        skuInfoList.removeAll(skuInfos);
        //  将最终的数据返回
        return skuInfoList;
    }

    @Override
    public Map<String, Object> findActivityRuleList(Long id) {
        //  先声明一个map 集合
        Map<String, Object> map = new HashMap<>();
        //  获取回显规则数据 activity_rule
        QueryWrapper<ActivityRule> activityRuleQueryWrapper = new QueryWrapper<>();
        activityRuleQueryWrapper.eq("activity_id",id);
        //  根据活动的Id 获取到活动规则列表集合
        List<ActivityRule> activityRuleList = activityRuleMapper.selectList(activityRuleQueryWrapper);

        //  这个key是谁 ： 页面需要渲染的key 是谁，那么我们这个key 就写谁！
        map.put("activityRuleList",activityRuleList);

        //  获取skuInfo列表数据 activity_sku
        QueryWrapper<ActivitySku> activitySkuQueryWrapper = new QueryWrapper<>();
        activitySkuQueryWrapper.eq("activity_id",id);
        //  根据活动Id 获取到活动相关的商品列表集合
        List<ActivitySku> activitySkuList = activitySkuMapper.selectList(activitySkuQueryWrapper);
        //  需要根据上述集合中的skuId 获取对应的skuInfo 列表数据！
        List<Long> skuIdList = activitySkuList.stream().map(ActivitySku::getSkuId).collect(Collectors.toList());
        //  此时根据skuIdList 获取到对应的skuInfo 集合数据
        List<SkuInfo> skuInfoList = productFeignClient.findSkuInfoBySkuIdList(skuIdList);

        //  存储数据即可
        map.put("skuInfoList",skuInfoList);

        //  回显活动的优惠券信息
        QueryWrapper<CouponInfo> couponInfoQueryWrapper = new QueryWrapper<>();
        couponInfoQueryWrapper.eq("activity_id",id);
        List<CouponInfo> couponInfoList = couponInfoMapper.selectList(couponInfoQueryWrapper);

        //  保存数据
        map.put("couponInfoList",couponInfoList);
        return map;
    }

    @Override
    public List<ActivityRule> findActivityRule(Long skuId) {
        //  查询到多个activityRule 的数据！
        //  商品详情页面中传入的数据集，只有一个skuId, 综上述所：也就是说需要进行多表关联查询！
        return activityInfoMapper.selectActivityRuleList(skuId);
    }

    /**
     *
     * @param cartInfoList  购物车中的所有购物项
     * @param skuIdToActivityIdMap
     * @return
     */
    @Override
    public List<CartInfoVo> findCartActivityRuleMap(List<CartInfo> cartInfoList,Map<Long, Long> skuIdToActivityIdMap) {
        //  准备完成实现！
        List<CartInfoVo> cartInfoVoList = new ArrayList<>();

        //  声明一个map 集合 skuIdToCartInfoMap key = skuId value = cartInfo;
        HashMap<Long, CartInfo> skuIdToCartInfoMap = new HashMap<>();
        //  循环遍历向集合中添加数
        for (CartInfo cartInfo : cartInfoList) {
            skuIdToCartInfoMap.put(cartInfo.getSkuId(),cartInfo);
        }
        //  声明一个变量
        //  如何实现分组： 根据什么判断每个购物项是否在同一组！
        //  先获取到skuIdList 集合
        List<Long> skuIdList = cartInfoList.stream().map(CartInfo::getSkuId).collect(Collectors.toList());
        //  根据skuIdList 这个条件查询到对应的活动规则集合 41,42,43
        List<ActivityRule> activityRuleList = activityInfoMapper.selectCartActivityRuleList(skuIdList);

        //  以skuId 为分组对象
        //  key = skuId value = List<ActivityRule>
        Map<Long, List<ActivityRule>> skuIdToActivityRuleListMap = activityRuleList.stream().collect(Collectors.groupingBy(activityRule -> activityRule.getSkuId()));

        //  将这个集合进行分组
        //  以活动Id 分析 key = activityId value = List<ActivityRule>
        Map<Long, List<ActivityRule>> activityIdToActivityRuleListAllMap = activityRuleList.stream().collect(Collectors.groupingBy(activityRule -> activityRule.getActivityId()));

        //  循环遍历这个集合
        Iterator<Map.Entry<Long, List<ActivityRule>>> iterator = activityIdToActivityRuleListAllMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<Long, List<ActivityRule>> entry = iterator.next();
            //  获取到集合对应的活动Id
            Long activityId = entry.getKey();
            //  活动Id 对应的活动规则列表
            List<ActivityRule> currentActivityRuleList = entry.getValue();
            //  活动规则列表需要做进一步的处理：去重操作！
            Set<Long> activitySkuIdSet = currentActivityRuleList.stream().map(ActivityRule::getSkuId).collect(Collectors.toSet());
            //  获取到去重之后的skuId列表！

            //  声明一个CartInfoVo 对象
            CartInfoVo cartInfoVo = new CartInfoVo();
            //  声明一个集合来存储cartInfoList 集合
            ArrayList<CartInfo> currentCartInfoList = new ArrayList<>();

            //  根据这个 skuId 获取到对应的cartInfo 对象
            //  循环遍历当前这个集合activitySkuIdSet
            for (Long skuId : activitySkuIdSet) {
                //  给skuIdToActivityIdMap 赋值
                skuIdToActivityIdMap.put(skuId,activityId);
                //  根据key 获取到了cartInfo 对象
                CartInfo cartInfo = skuIdToCartInfoMap.get(skuId);
                currentCartInfoList.add(cartInfo);
            }
            //  赋值购物项集合数据
            cartInfoVo.setCartInfoList(currentCartInfoList);
            //  赋值促销活动规则集合！ activitySkuIdSet.iterator().next() 获取到的就是一个skuId ;
            //  activitySkuIdSet 这个集合中所有的skuId 对应的促销规则都是一样的！所以我只要获取其中一个就可以了！
            List<ActivityRule> skuActivityRuleList = skuIdToActivityRuleListMap.get(activitySkuIdSet.iterator().next());
            cartInfoVo.setActivityRuleList(skuActivityRuleList);

            //  将cartInfoVo 对象添加到集合中
            cartInfoVoList.add(cartInfoVo);
        }

        //  返回数据
        return cartInfoVoList;
    }

    @Override
    public Map<Long, ActivityRule> findTradeActivityRuleMap(List<OrderDetail> orderDetailList) {
        //  声明一个集合 key = activityId value = ActivityRule;
        Map<Long, ActivityRule> activityRuleMap = new HashMap<>();
        //  声明一个集合来存储 skuId 对应的订单明细
        Map<Long,OrderDetail> skuIdToOrderDetailMap = new HashMap<>();
        //  循环遍历当前这个集合orderDetailList
        for (OrderDetail orderDetail : orderDetailList) {
            skuIdToOrderDetailMap.put(orderDetail.getSkuId(),orderDetail);
        }

        //  先获取到skuIdList 集合！
        List<Long> skuIdList = orderDetailList.stream().map(OrderDetail::getSkuId).collect(Collectors.toList());

        //  获取到对应的活动规则
        List<ActivityRule> activityRuleList = activityInfoMapper.selectCartActivityRuleList(skuIdList);

        //  以skuId 为分组，获取到数据！
        Map<Long, List<ActivityRule>> skuIdToActivityRuleMap = activityRuleList.stream().collect(Collectors.groupingBy(activityRule -> activityRule.getSkuId()));
        //  以活动Id 进行分组
        Map<Long, List<ActivityRule>> activityIdToActivityRuleMap = activityRuleList.stream().collect(Collectors.groupingBy(activityRule -> activityRule.getActivityId()));

        //  循环遍历当前这个map 集合
        Iterator<Map.Entry<Long, List<ActivityRule>>> iterator = activityIdToActivityRuleMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<Long, List<ActivityRule>> entry = iterator.next();
            //  获取到活动Id
            Long activityId = entry.getKey();
            List<ActivityRule> activityRulesList = entry.getValue();
            //  获取到这个活动规则所对应的skuId
            Set<Long> activitySkuIdSet = activityRulesList.stream().map(activityRule -> activityRule.getSkuId()).collect(Collectors.toSet());
            //  循环遍历当前集合 activitySkuIdSet 这个集合中存储的是 当前这个活动对应的skuId!
            BigDecimal activityTotalAmount = new BigDecimal("0");

            //  声明一个变量来记录当前商品的总件数！
            Integer activityTotalNum = 0;
            for (Long skuId : activitySkuIdSet) {
                //   1.   得到当前订单明细中单个商品的总价价格：
                OrderDetail orderDetail = skuIdToOrderDetailMap.get(skuId);
                //  单价*数量
                BigDecimal skuTotalAmount = orderDetail.getOrderPrice().multiply(new BigDecimal(orderDetail.getSkuNum()));
                //  2.  将每个订单明细中的商品价格进行相加！
                activityTotalAmount = activityTotalAmount.add(skuTotalAmount);

                //  3.  活动有两种类型： 一种 满减 一种 打折，折扣
                activityTotalNum += orderDetail.getSkuNum();
            }
            //  根据 skuId 获取到活动规则列表！
            List<ActivityRule> skuActivityRuleList = skuIdToActivityRuleMap.get(activitySkuIdSet.iterator().next());
            //  遍历当前的活动规则列表
            for (ActivityRule activityRule : skuActivityRuleList) {
                //   活动有两种类型： 一种 满减 一种 打折，折扣
                //  先判断满减类型
                if (activityRule.getActivityType().equals(ActivityType.FULL_REDUCTION.name())){
                    //  判断   订单中的总金额 > 满减金额
                    if (activityTotalAmount.compareTo(activityRule.getConditionAmount())>-1){
                        //  设置满减的规则  优惠后减少金额！  优惠金额
                        activityRule.setReduceAmount(activityRule.getBenefitAmount());
                        //  将对应的skuId 赋值给 activityRule
                        activityRule.setSkuIdList(new ArrayList<>(activitySkuIdSet));
                        //  将活动Id ，活动规则放入集合
                        activityRuleMap.put(activityRule.getActivityId(),activityRule);
                        break;
                    }
                }else {
                    //  打折 ，折扣 总件数>=满减件数 属于打折
                    if (activityTotalNum>=activityRule.getConditionNum()){
                        //  商品：1000 8折  1000*8/10
                        //  计算出当前的打折的价格！  总价*优惠折扣/10
                        BigDecimal skuDiscountTotalAmount = activityTotalAmount.multiply(activityRule.getBenefitDiscount()).divide(new BigDecimal("10"));
                        //  用总价 - 折扣价
                        activityRule.setReduceAmount(activityTotalAmount.subtract(skuDiscountTotalAmount));
                        //  将对应的skuId 赋值给 activityRule
                        activityRule.setSkuIdList(new ArrayList<>(activitySkuIdSet));
                        //  将活动Id ，活动规则放入集合
                        activityRuleMap.put(activityRule.getActivityId(),activityRule);
                        break;
                    }
                }
            }
        }
        //  返回数据  activityId  与  activityRule 活动规则！
        return activityRuleMap;
    }


}
